
package com.hlkj.pay.app.merchant.ext.impl.yeepay.ext;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import com.hlkj.pay.app.merchant.ext.MerchantExtConstant;
import com.hlkj.pay.app.merchant.ext.impl.yeepay.dto.YeePayDivideDetail;
import com.hlkj.pay.dto.order.PayOrderFundDto;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.enums.PayOrderEnums;
import jodd.util.StringPool;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.extension.annotation.Extension;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.yeepay.YeePayScenePayOrderExtPt;
import com.hlkj.pay.app.merchant.ext.impl.yeepay.constant.YeePayExtConstant;
import com.hlkj.pay.app.merchant.ext.impl.yeepay.dto.YeePayAppChannelParams;
import com.hlkj.pay.app.merchant.ext.impl.yeepay.dto.YeePayConfig;
import com.hlkj.pay.app.merchant.ext.impl.yeepay.handler.YeePayCommonParamsHandle;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.vo.order.req.PayOrderCommonParamReq;
import com.yeepay.yop.sdk.auth.credentials.PKICredentialsItem;
import com.yeepay.yop.sdk.auth.credentials.YopPKICredentials;
import com.yeepay.yop.sdk.security.CertTypeEnum;
import com.yeepay.yop.sdk.service.aggpay.AggpayClient;
import com.yeepay.yop.sdk.service.aggpay.AggpayClientBuilder;
import com.yeepay.yop.sdk.service.aggpay.model.OrderResponseDTO;
import com.yeepay.yop.sdk.service.aggpay.request.PrePayRequest;
import com.yeepay.yop.sdk.service.aggpay.response.PrePayResponse;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 小程序统一下单
 *
 * @author HlpayTeam
 * @date 2024/11/18 13:07
 */
@Slf4j
@Repository
@RequiredArgsConstructor
@Extension(bizId = YeePayExtConstant.MINI_APP)
public class YeePayMiniPayOrderExtPt extends YeePaySceneCommonPayOrder implements YeePayScenePayOrderExtPt {

    private final YeePayCommonParamsHandle yeePayCommonParamsHandle;

    private static final AggpayClient api = AggpayClientBuilder.builder().build();

    @Override
    public void submitChannelPayOrder(ChannelPayOrderContext channelPayOrderContext) {

        log.info("易宝 MINI 请求参数:{}", JsonUtils.toJsonString(channelPayOrderContext));
        ProviderChannelConfigDO providerChannelConfigDO = channelPayOrderContext.getProviderChannelConfigDO();
        CommonResult<YeePayConfig> yeePayConfigCommonResult = yeePayCommonParamsHandle.yeePayConfig(providerChannelConfigDO,
                channelPayOrderContext.isTest());
        if (!yeePayConfigCommonResult.isSuccess()) {
            channelPayOrderContext.setRemark(yeePayConfigCommonResult.getMsg());
            channelPayOrderContext.setProcessStatus(false);
            return;
        }
        // 支付订单信息
        PayOrderDO payOrderDO = channelPayOrderContext.getPayOrderDO();
        // 支付方式信息
        PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
        // 商户通道信息
        MerchantAppChannelDO merchantAppChannelDO = channelPayOrderContext.getMerchantAppChannelDO();
        // 额外参数信息
        PayOrderCommonParamReq.Extra extra = channelPayOrderContext.getExtra();
        // 易宝配置信息
        YeePayConfig yeePayConfig = yeePayConfigCommonResult.getData();

        if (extra == null || !StringUtils.hasText(extra.getUserId())) {
            channelPayOrderContext.setProcessStatus(Boolean.FALSE);
            channelPayOrderContext.setRemark("易宝 "+ PayEnums.PAY_TYPE.fromByCode(payWayDO.getType()).getType() +" 提交 MINI_APP 支付 没有提交userId");
            return;
        }

        try {
            YeePayAppChannelParams yeeAppChannelParams = JsonUtils.parseObject(merchantAppChannelDO.getAppConfigJson(), YeePayAppChannelParams.class);

            PrePayRequest request = new PrePayRequest();
            String appKey = yeePayConfig.getAppId();
            request.getRequestConfig().setAppKey(appKey);
            request.getRequestConfig().setCredentials(new YopPKICredentials(
                    appKey, new PKICredentialsItem(YeePayCommonParamsHandle.getPrivateKey(
                    yeePayConfig.getPrivateKey(),
                    CertTypeEnum.RSA2048),
                    CertTypeEnum.RSA2048)));

            // 失效时间
            request.setExpiredTime(yeePayCommonParamsHandle.formatTimestamp(payOrderDO.getExpiredTime()));

            // 上级商户编号
            if(StrUtil.isEmpty(yeePayConfig.getPlatformNo())){
                request.setParentMerchantNo(yeePayConfig.getMchId());
            }else{
                request.setParentMerchantNo(yeePayConfig.getPlatformNo());
            }

            String payway = yeePayCommonParamsHandle.getPayWay(payWayDO);
            if(StrUtil.isEmpty(payway)){
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                channelPayOrderContext.setRemark("易宝提交MINI_APP支付 支付类型: "+payWayDO.getType()+" 不支持");
                return;
            }
            request.setPayWay(payway);

            String getPayChannel = yeePayCommonParamsHandle.getPayChannel(payWayDO);
            if(StrUtil.isEmpty(getPayChannel)){
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                channelPayOrderContext.setRemark("易宝提交MINI_APP支付 渠道类型: "+payWayDO.getType()+" 不支持");
                return;
            }
            request.setChannel(getPayChannel);
            request.setScene(yeePayCommonParamsHandle.getPayScene(payWayDO));
            request.setUserIp(payOrderDO.getClientIp());
            request.setMerchantNo(yeeAppChannelParams.getSubMchId());
            request.setOrderId(payOrderDO.getPayOrderNo());
            request.setOrderAmount(NumberUtil.round(payOrderDO.getAmount(),2,RoundingMode.HALF_UP));
            request.setAppId(extra.getSubAppid());
            request.setUserId(extra.getUserId());
            request.setGoodsName(payOrderDO.getSubject());
            request.setNotifyUrl(channelPayOrderContext.getNotifyUrl());

            // 清算通知
            request.setCsUrl(domain + MerchantExtConstant.MERCHANT_ORDER_CS_CALLBACK_URL + payOrderDO.getChannelCode() + StringPool.SLASH + payOrderDO.getProviderCode());
            // 分账
            if(payOrderDO.getFundProcessType() != null){
                switch (PayOrderEnums.FUND_PROCESS_TYPE.from(payOrderDO.getFundProcessType())){
                    case REAL_TIME:
                        // 分账信息
                        List<PayOrderFundDto> payOrderFundDtos = JsonUtils.parseArray(payOrderDO.getAcctInfoJson(), PayOrderFundDto.class);
                        // 实时分账类型
                        request.setFundProcessType("REAL_TIME_DIVIDE");
                        // 组装分账详情
                        List<YeePayDivideDetail> divideDetails = new ArrayList<>();
                        for(PayOrderFundDto fundDto: payOrderFundDtos){
                            YeePayDivideDetail divideDetail = new YeePayDivideDetail();
                            divideDetail.setAmount(NumberUtil.roundStr(fundDto.getAmount(), 2, RoundingMode.HALF_UP));
                            divideDetail.setLedgerNo(fundDto.getAccountNo());
                            divideDetail.setDivideDetailDesc(fundDto.getDescription());
                            divideDetails.add(divideDetail);
                        }
                        request.setDivideDetail(JsonUtils.toJsonString(divideDetails));
                        request.setDivideNotifyUrl(domain + MerchantExtConstant.MERCHANT_ORDER_DIVICE_CALLBACK_URL + payOrderDO.getChannelCode() +
                                StringPool.SLASH + payOrderDO.getProviderCode()+ StringPool.SLASH + payOrderFundDtos.get(0).getBatchNo()
                        );
                    case DELAY_TIME:
                        request.setFundProcessType("DELAY_SETTLE");
                        break;
                }
            }

            // 营销补贴 易宝目前只支持补贴商户,调用接口时必须判断清算状态是否成功
            if(payOrderDO.getMarketProcessType() != null){
                switch (PayOrderEnums.PAY_ORDER_SUBSIDY_TYPE.from(payOrderDO.getMarketProcessType())){
                    case CUSTOM_ALLOWANCE:
                        // 营销信息
                        // OrderPromotionInfo promotionInfo = JSONUtil.toBean(payOrderDO.getMarketingOrdersJson(),OrderPromotionInfo.class);
                        Map<String,String> ypPromotionInfo = new HashMap<>();
                        ypPromotionInfo.put("type","CUSTOM_ALLOWANCE");
                        request.setYpPromotionInfo(JSONUtil.toJsonStr(CollUtil.newArrayList(ypPromotionInfo)));
                        // 自定义金额补贴营销信息默认空，掉接口再传
                        payOrderDO.setMarketingOrdersJson(null);
                        break;
                }
            }

            log.info("易宝提交MINI_APP支付 请求参数:{}", JSONUtil.toJsonStr(request));
            PrePayResponse response = api.prePay(request);
            OrderResponseDTO result = response.getResult();
            log.info("易宝提交MINI_APP支付 返回参数:{}", JSONUtil.toJsonStr(result));

            if ("00000".equals(result.getCode())) {
                switch (getPayChannel){
                    // 微信小程序
                    case "WECHAT":
                        channelPayOrderContext.setPayDataType("data");
                        channelPayOrderContext.setPayInfo(JSONUtil.toJsonStr(result.getPrePayTn()));
                        break;

                    // 支付宝小程序
                    case "ALIPAY":
                        channelPayOrderContext.setPayDataType("data");
                        channelPayOrderContext.setPayInfo(result.getPrePayTn());
                        break;
                }
            }else{
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                channelPayOrderContext.setRemark("易宝提交MINI_APP支付 请求失败, fail: " + result.getMessage());
            }
        }catch (Exception e) {
            e.printStackTrace();
            channelPayOrderContext.setRemark("易宝提交MINI_APP支付 请求失败, error: " + e.getMessage());
            channelPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    @Override
    public void queryChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void closeChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonCloseChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void queryChannelClosePayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelClosePayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void refundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public void queryRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonQueryRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public boolean refundApply(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        return true;
    }

    @Override
    public CommonResult<String> channelOrderCode(ChannelPayOrderContext channelPayOrderContext) {
        return CommonResult.success();
    }
}
